#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <iostream>

#include <boost/timer.hpp>
#include <boost/shared_ptr.hpp>
#include <boost/bind.hpp>

#include <boost/date_time/posix_time/posix_time.hpp>
#include <boost/date_time/gregorian/gregorian.hpp>

using namespace boost::posix_time;
using namespace boost::gregorian;


int main( int argc, char *argv[] )
{
	const char *opt_str = "s" // sync
		"a" // append;
		"b:" // block size
		"c:" // count
		;

	int open_flag = O_CREAT | O_WRONLY;
	int block_size = 100;
	int count = 1000;
	int op;
	while( (op = getopt( argc, argv, opt_str )) != -1 ) {
		switch( op ) {
		case 's':
			open_flag |= O_SYNC;
			break;
		case 'a':
			open_flag |= O_APPEND;
			break;
		case 'b':
			block_size = atoi( optarg );
			break;
		case 'c':
			count = atoi( optarg );
			break;
		default:
			exit( EXIT_FAILURE );
		}
	}
	const char * file = "write_test";
	if( argc > optind ) {
		file = argv[optind];
	}

	int fd = open( file, open_flag, 0644 );
	if( fd < 0 ) {
		fprintf( stderr, "open file failed, file %s", file );
		exit( EXIT_FAILURE );
	}
	boost::shared_ptr< void > close_guard( (void *)0, boost::bind( close, fd ) );
	char *buf = (char *)malloc(block_size);
	boost::shared_ptr< void > free_guard( (void *)0, boost::bind( free, buf) );

	ptime start_time = microsec_clock::universal_time();
	int n;
	uint32_t offset = 0;
	for( int i = 0; i < count; i ++ ) {
		if( open_flag & O_APPEND ) {
			n = write( fd, buf, block_size );
		}
		else {
			n = pwrite( fd, buf, block_size, offset );
			offset += n;
		}
		if( n < 0 ) {
			fprintf( stderr, "write error, file %s", file );
			exit( EXIT_FAILURE );
		}

		if( ! (i % 50) ) {
			time_duration duration = microsec_clock::universal_time() - start_time;
			std::cout << "I: " << i  << "  " << "time now: " << duration.total_milliseconds() << "(ms)" << std::endl;
		}
	}
	time_duration duration = microsec_clock::universal_time() - start_time;
	std::cout << "time total: " << duration.total_milliseconds() << "(ms)" << std::endl;

	return 0;
}
